{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5a7cca87-7472-48ab-9faa-ee532a8203e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "import os\n",
    "import io\n",
    "from openai import OpenAI\n",
    "from langchain_openai import ChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a1f69ce6-3930-4649-b252-7a99d92923dd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载 .env 文件中的环境变量\n",
    "load_dotenv()\n",
    "# 要在地址后面加上版本号\n",
    "base_url = \"http://direct.virtaicloud.com:44404/v1\"\n",
    "api_key = os.getenv(\"virtaicloud_api_key\")\n",
    "modelname = \"sft4-6-1-final\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "0355314b-5737-4d68-a203-322c145da0be",
   "metadata": {},
   "outputs": [],
   "source": [
    "client = OpenAI(\n",
    "    api_key=api_key,\n",
    "    base_url=base_url\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "edf2f598-78ac-4f4d-b595-0013b5582f4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import base64\n",
    "# 输入套模板\n",
    "from langchain_core.prompts import SystemMessagePromptTemplate\n",
    "from langchain_core.prompts import HumanMessagePromptTemplate\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from PIL import Image\n",
    "import numpy as np\n",
    "from io import BytesIO\n",
    "import json\n",
    "import sys\n",
    "from tqdm import tqdm\n",
    "import datetime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1ac054b5-a6d1-4f5d-8b86-33992dd40aa3",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"role\": \"user\",\n",
      "    \"content\": [\n",
      "        {\n",
      "            \"type\": \"image_url\",\n",
      "            \"image_url\": {\n",
      "                \"url\": \"\"\n",
      "            }\n",
      "        },\n",
      "        {\n",
      "            \"type\": \"text\",\n",
      "            \"text\": \"你是一个电商客服专家，请根据用户与客服的多轮对话判断用户的意图分类标签。\\n<用户与客服的对话 START>\\n用户: <http>\\n客服: \\\"建议您关注一下我们的成套优惠活动： 购买指定的晾衣机，将免费获赠一款洗衣机 晾衣机型号【HL-QS23SU1】 ①采用三重防护新标准，包括防漏电、防燃烧和防跌落。 ②配备柔光大屏幕，照明范围可达20平方米 ③设计为纤薄全嵌式，可完美嵌入阳台空间 <http>\\\"\\n用户: <image>\\n客服: 重磅消息【大家期待已久的市政府补贴活动来了】!! 【以旧换新 市政府补贴】特定型号的一级能效产品可享受八折优惠，二级能效产品可享受八五折优惠，单件最高可减2000元，八大类别均可享受立即下单立减的优惠； 赶紧点击链接领取福利吧→<http> 【库存有限，先到先得，机会难得】\\n用户: 您好，洗衣机关于排水口的问题\\n客服: 亲爱的顾客，关于波轮式洗衣机：它们都是采用下排水设计的。至于滚筒式洗衣机：型号中包含X的表示下排水，没有X的则是上排水设计。（需要注意的是，MAX是特定系列的标识，这里的X并不意味着下排水） 您可以查看商品页面中的详细信息或规格参数来了解具体产品的排水方式。如果您有疑问，比如询问“这款是上排水吗”，我们的在线客服助手会帮您查询的。\\n用户: 刚装上就出问题了\\n客服: 您可以在微信搜索“家电服务”小程序或扫描下方二维码，在线申请安装、维修、移机、清洗等服务，我们的客服团队会为您安排专业技术人员上门服务；在保修期内，性能问题的处理是免费的，如果需要收费，技术人员会按照统一收费标准向您说明。\\n用户: 出现了漏水情况\\n客服: 亲爱的顾客，非常抱歉给您带来了不便。如果商品出现问题，您可以通过搜索小程序【家电服务助手】来预约专业人员上门服务。温馨提示：①如果您购买的商品在15天内出现质量问题，经过鉴定符合要求的话，我们提供退换服务；②如果超过15天但在保修期内，性能问题可以免费维修；如涉及收费项目，工作人员会按照统一标准向您展示费用。\\n<用户与客服的对话 END>\\n请直接只输出分类标签结果，不需要其他多余的话。以下是可以参考的分类标签为：[\\\"反馈密封性不好\\\",\\\"是否好用\\\",\\\"是否会生锈\\\",\\\"排水方式\\\",\\\"包装区别\\\",\\\"发货数量\\\",\\\"反馈用后症状\\\",\\\"商品材质\\\",\\\"功效功能\\\",\\\"是否易褪色\\\",\\\"适用季节\\\",\\\"能否调光\\\",\\\"版本款型区别\\\",\\\"单品推荐\\\",\\\"用法用量\\\",\\\"控制方式\\\",\\\"上市时间\\\",\\\"商品规格\\\",\\\"信号情况\\\",\\\"养护方法\\\",\\\"套装推荐\\\",\\\"何时上货\\\",\\\"气泡\\\"]\\n\"\n",
      "        }\n",
      "    ]\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "# 定义模板字符串\n",
    "image_path = \"E:\\\\fxuanf\\\\02_AI_51\\\\01_Projects\\\\doraemon-bot\\\\datasets\\\\test1\\\\images\\\\21084b9217277750918824374d0ac0-0.jpg\"\n",
    "with open(image_path, \"rb\") as image_file:\n",
    "    encoded_string = base64.b64encode(image_file.read()).decode()\n",
    "\n",
    "image_url = f\"data:image/png;base64,{encoded_string}\"\n",
    "\n",
    "template = (\n",
    "    \"你是一个电商客服专家，请根据用户与客服的多轮对话判断用户的意图分类标签。\\n\"\n",
    "    \"<用户与客服的对话 START>\\n\"\n",
    "    \"用户: <http>\\n\"\n",
    "    \"客服: \\\"建议您关注一下我们的成套优惠活动： 购买指定的晾衣机，将免费获赠一款洗衣机 晾衣机型号【HL-QS23SU1】 ①采用三重防护新标准，包括防漏电、防燃烧和防跌落。 ②配备柔光大屏幕，照明范围可达20平方米 ③设计为纤薄全嵌式，可完美嵌入阳台空间 <http>\\\"\\n\"\n",
    "    \"用户: <image>\\n\"\n",
    "    \"客服: 重磅消息【大家期待已久的市政府补贴活动来了】!! 【以旧换新 市政府补贴】特定型号的一级能效产品可享受八折优惠，二级能效产品可享受八五折优惠，单件最高可减2000元，八大类别均可享受立即下单立减的优惠； 赶紧点击链接领取福利吧→<http> 【库存有限，先到先得，机会难得】\\n\"\n",
    "    \"用户: 您好，洗衣机关于排水口的问题\\n\"\n",
    "    \"客服: 亲爱的顾客，关于波轮式洗衣机：它们都是采用下排水设计的。至于滚筒式洗衣机：型号中包含X的表示下排水，没有X的则是上排水设计。（需要注意的是，MAX是特定系列的标识，这里的X并不意味着下排水） 您可以查看商品页面中的详细信息或规格参数来了解具体产品的排水方式。如果您有疑问，比如询问“这款是上排水吗”，我们的在线客服助手会帮您查询的。\\n\"\n",
    "    \"用户: 刚装上就出问题了\\n\"\n",
    "    \"客服: 您可以在微信搜索“家电服务”小程序或扫描下方二维码，在线申请安装、维修、移机、清洗等服务，我们的客服团队会为您安排专业技术人员上门服务；在保修期内，性能问题的处理是免费的，如果需要收费，技术人员会按照统一收费标准向您说明。\\n\"\n",
    "    \"用户: 出现了漏水情况\\n\"\n",
    "    \"客服: 亲爱的顾客，非常抱歉给您带来了不便。如果商品出现问题，您可以通过搜索小程序【家电服务助手】来预约专业人员上门服务。温馨提示：①如果您购买的商品在15天内出现质量问题，经过鉴定符合要求的话，我们提供退换服务；②如果超过15天但在保修期内，性能问题可以免费维修；如涉及收费项目，工作人员会按照统一标准向您展示费用。\\n\"\n",
    "    \"<用户与客服的对话 END>\\n\"\n",
    "    \"请直接只输出分类标签结果，不需要其他多余的话。以下是可以参考的分类标签为：[\\\"反馈密封性不好\\\",\\\"是否好用\\\",\\\"是否会生锈\\\",\\\"排水方式\\\",\\\"包装区别\\\",\\\"发货数量\\\",\\\"反馈用后症状\\\",\\\"商品材质\\\",\\\"功效功能\\\",\\\"是否易褪色\\\",\\\"适用季节\\\",\\\"能否调光\\\",\\\"版本款型区别\\\",\\\"单品推荐\\\",\\\"用法用量\\\",\\\"控制方式\\\",\\\"上市时间\\\",\\\"商品规格\\\",\\\"信号情况\\\",\\\"养护方法\\\",\\\"套装推荐\\\",\\\"何时上货\\\",\\\"气泡\\\"]\\n\"\n",
    ")\n",
    "\n",
    "# 创建 HumanMessagePromptTemplate 实例\n",
    "human_message_prompt = HumanMessagePromptTemplate.from_template(template=template)\n",
    "\n",
    "# 提供具体的文本和图像URL\n",
    "formatted_message = human_message_prompt.format(\n",
    "    text=\"你是一个电商客服专家，请根据用户与客服的多轮对话判断用户的意图分类标签。\"\n",
    ")\n",
    "\n",
    "# 构建最终的JSON结构\n",
    "message_json = {\n",
    "    \"role\": \"user\",\n",
    "    \"content\": [\n",
    "        {\"type\": \"image_url\", \"image_url\": {\"url\": image_url}},\n",
    "        {\"type\": \"text\", \"text\": formatted_message.content}\n",
    "    ]\n",
    "}\n",
    "\n",
    "# 输出 JSON 结构\n",
    "import json\n",
    "print(json.dumps(message_json, ensure_ascii=False, indent=4))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b3f7eacb-4c99-4c95-8f1f-14a63664e3d8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "反馈密封性不好\n"
     ]
    }
   ],
   "source": [
    "completion = client.chat.completions.create(\n",
    "    model=modelname,\n",
    "    messages=[\n",
    "        {\"role\": \"user\", \"content\": [\n",
    "            {\"type\": \"image_url\", \"image_url\": {\"url\": image_url}},\n",
    "            {\"type\": \"text\", \"text\": \"你是一个电商客服专家，请根据用户与客服的多轮对话判断用户的意图分类标签。\\n<用户与客服的对话 START>\\n用户: <http>\\n客服: \\\"建议您关注一下我们的成套优惠活动： 购买指定的晾衣机，将免费获赠一款洗衣机 晾衣机型号【HL-QS23SU1】 ①采用三重防护新标准，包括防漏电、防燃烧和防跌落。 ②配备柔光大屏幕，照明范围可达20平方米 ③设计为纤薄全嵌式，可完美嵌入阳台空间 <http>\\\"\\n用户: <image>\\n客服: 重磅消息【大家期待已久的市政府补贴活动来了】!! 【以旧换新 市政府补贴】特定型号的一级能效产品可享受八折优惠，二级能效产品可享受八五折优惠，单件最高可减2000元，八大类别均可享受立即下单立减的优惠； 赶紧点击链接领取福利吧→<http> 【库存有限，先到先得，机会难得】\\n用户: 您好，洗衣机关于排水口的问题\\n客服: 亲爱的顾客，关于波轮式洗衣机：它们都是采用下排水设计的。至于滚筒式洗衣机：型号中包含X的表示下排水，没有X的则是上排水设计。（需要注意的是，MAX是特定系列的标识，这里的X并不意味着下排水） 您可以查看商品页面中的详细信息或规格参数来了解具体产品的排水方式。如果您有疑问，比如询问“这款是上排水吗”，我们的在线客服助手会帮您查询的。\\n用户: 刚装上就出问题了\\n客服: 您可以在微信搜索“家电服务”小程序或扫描下方二维码，在线申请安装、维修、移机、清洗等服务，我们的客服团队会为您安排专业技术人员上门服务；在保修期内，性能问题的处理是免费的，如果需要收费，技术人员会按照统一收费标准向您说明。\\n用户: 出现了漏水情况\\n客服: 亲爱的顾客，非常抱歉给您带来了不便。如果商品出现问题，您可以通过搜索小程序【家电服务助手】来预约专业人员上门服务。温馨提示：①如果您购买的商品在15天内出现质量问题，经过鉴定符合要求的话，我们提供退换服务；②如果超过15天但在保修期内，性能问题可以免费维修；如涉及收费项目，工作人员会按照统一标准向您展示费用。\\n<用户与客服的对话 END>\\n请直接只输出分类标签结果，不需要其他多余的话。以下是可以参考的分类标签为：[\\\"反馈密封性不好\\\",\\\"是否好用\\\",\\\"是否会生锈\\\",\\\"排水方式\\\",\\\"包装区别\\\",\\\"发货数量\\\",\\\"反馈用后症状\\\",\\\"商品材质\\\",\\\"功效功能\\\",\\\"是否易褪色\\\",\\\"适用季节\\\",\\\"能否调光\\\",\\\"版本款型区别\\\",\\\"单品推荐\\\",\\\"用法用量\\\",\\\"控制方式\\\",\\\"上市时间\\\",\\\"商品规格\\\",\\\"信号情况\\\",\\\"养护方法\\\",\\\"套装推荐\\\",\\\"何时上货\\\",\\\"气泡\\\"]\\n\"}\n",
    "        ]}\n",
    "    ]\n",
    ")\n",
    "\n",
    "print(completion.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f69df898-f430-4d80-98de-a13a8fed6168",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "反馈密封性不好\n"
     ]
    }
   ],
   "source": [
    "completion = client.chat.completions.create(\n",
    "    model=modelname,\n",
    "    messages=[message_json]\n",
    ")\n",
    "\n",
    "print(completion.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e4c8d24-8303-4f4d-9f4b-a7a6e0596ffd",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "4d450799-7cd1-4aac-8424-34fc37686bbb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "这是一张照片，展示了一位女士和她的狗在海滩上玩耍的场景。女士穿着格子衬衫，坐在沙滩上，她的狗是一只大型犬，伸出它的前爪与女士碰触，似乎在进行“握手”的游戏。背景是远处的海浪和夕阳的余晖，整个画面充满了温馨和快乐的气氛。\n"
     ]
    }
   ],
   "source": [
    "completion = client.chat.completions.create(\n",
    "    model=modelname,\n",
    "    messages=[\n",
    "        {\"role\": \"user\", \"content\": [\n",
    "            {\"type\": \"image_url\", \"image_url\": {\"url\": \"https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20241022/emyrja/dog_and_girl.jpeg\"}},\n",
    "            {\"type\": \"text\", \"text\": \"这是什么？\"}\n",
    "        ]}\n",
    "    ]\n",
    ")\n",
    "\n",
    "print(completion.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54fd77d4-f311-435f-bb5b-1fbc075b212e",
   "metadata": {},
   "source": [
    "# LangChain\n",
    "1. 输入预处理\n",
    "2. 调用大模型\n",
    "3. 输出后处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "29c9808d-5d10-4e64-8e3b-1a5c1f93864e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_data_from_json(file_path):\n",
    "    \"\"\"\n",
    "    从指定路径加载JSON文件内容。\n",
    "    \n",
    "    :param file_path: JSON文件的路径\n",
    "    :return: JSON解析后的内容，如果文件不存在或解析失败则返回None\n",
    "    \"\"\"\n",
    "    try:\n",
    "        with open(file_path, 'r', encoding='utf-8') as file:\n",
    "            content = file.read().strip()\n",
    "            if not content:\n",
    "                print(\"文件为空\")\n",
    "                return None\n",
    "            return json.loads(content)\n",
    "    except (FileNotFoundError, json.JSONDecodeError) as e:\n",
    "        print(f\"加载文件 {file_path} 出现问题: {e}\")\n",
    "        return None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "18ac3dd9-d285-4e60-b982-dbb521620608",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "E:\\fxuanf\\02_AI_51\\01_Projects\\doraemon-bot\\datasets\\test1\\test1_fullpath.json\n"
     ]
    }
   ],
   "source": [
    "root_dir = \"E:\\\\\"\n",
    "code_path = os.path.join(root_dir, \"fxuanf\", \"02_AI_51\", \"01_Projects\", \"doraemon-bot\")\n",
    "code_datasets_path = os.path.join(code_path, \"datasets\")\n",
    "test1_path = os.path.join(code_datasets_path, \"test1\",)\n",
    "image_path = os.path.join(code_datasets_path, \"images\")\n",
    "\n",
    "test1_file_path = os.path.join(test1_path, \"test1.json\")\n",
    "test1_file_fullpath = os.path.join(code_datasets_path, \"test1\", \"test1_fullpath.json\")\n",
    "print(test1_file_fullpath)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "5fa4917b-2e59-4715-a766-989d1dd2b0fc",
   "metadata": {},
   "outputs": [],
   "source": [
    "def save_results_to_json(results, output_file, batch_size=1000):\n",
    "    try:\n",
    "        with open(output_file, 'a', encoding='utf-8') as f:\n",
    "            batch = []\n",
    "            for i, result in enumerate(results):\n",
    "                batch.append(json.dumps(result, ensure_ascii=False))\n",
    "                if (i + 1) % batch_size == 0:\n",
    "                    f.write('\\n'.join(batch) + '\\n')\n",
    "                    batch = []\n",
    "            if batch:\n",
    "                f.write('\\n'.join(batch) + '\\n')\n",
    "    except IOError as e:\n",
    "        print(f\"An IOError occurred: {e}\")\n",
    "    except Exception as e:\n",
    "        print(f\"An unexpected error occurred: {e}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "f65a3740-bbb5-4bc4-9f80-edba1f0fc75f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 假设 get_model_response 函数和 data, image_path 已经定义好了\n",
    "\n",
    "# JSON 文件路径\n",
    "json_file_path = 'results.json'\n",
    "\n",
    "def save_to_json(new_result):\n",
    "    # 读取现有的结果列表或初始化为空列表\n",
    "    if os.path.exists(json_file_path):\n",
    "        with open(json_file_path, mode='r', encoding='utf-8') as file:\n",
    "            results = json.load(file)\n",
    "    else:\n",
    "        results = []\n",
    "\n",
    "    # 添加新的结果到列表中\n",
    "    results.append(new_result)\n",
    "\n",
    "    # 将更新后的结果列表写回JSON文件\n",
    "    with open(json_file_path, mode='w', encoding='utf-8') as file:\n",
    "        json.dump(results, file, ensure_ascii=False, indent=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a11622bb-3faa-4630-a8cc-eba56e899c2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def image_to_base64(image_path, max_size=(640, 640)):\n",
    "    try:\n",
    "        # 打开图像文件\n",
    "        with Image.open(image_path) as img:\n",
    "            # 如果图像模式不是RGB，则转换为RGB\n",
    "            if img.mode != 'RGB':\n",
    "                img = img.convert('RGB')\n",
    "\n",
    "            # 计算新的尺寸以保持纵横比\n",
    "            img.thumbnail(max_size)\n",
    "\n",
    "            # 创建一个内存中的字节流用于保存调整后的图像\n",
    "            buffered = io.BytesIO()\n",
    "            \n",
    "            # 将图像保存到内存字节流中，格式为JPEG\n",
    "            img.save(buffered, format=\"JPEG\")\n",
    "\n",
    "            # 获取字节流中的数据并进行Base64编码\n",
    "            img_str = base64.b64encode(buffered.getvalue()).decode('utf-8')\n",
    "            \n",
    "            return img_str\n",
    "    except Exception as e:\n",
    "        print(f\"Error processing image: {e}\")\n",
    "        return None\n",
    "\n",
    "def preprocess_image(image_path, target_size=(640, 640)):\n",
    "    image = Image.open(image_path).convert('RGB')\n",
    "    image = image.resize(target_size)\n",
    "    image_np = np.array(image)\n",
    "    # 归一化或其他预处理步骤可以根据模型需求添加\n",
    "    return image_np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "00f2747f-ddec-4b27-b38c-a3a013eea8d2",
   "metadata": {},
   "outputs": [],
   "source": [
    "client = OpenAI(\n",
    "    api_key=api_key,\n",
    "    base_url=base_url\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "6bcb0261-2c6f-45ef-b3be-357e3308e58c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_processed_ids(file_path):\n",
    "    \"\"\"加载已经处理过的 item_id 列表\"\"\"\n",
    "    if not os.path.exists(file_path):\n",
    "        return set()\n",
    "    with open(file_path, 'r') as f:\n",
    "        return set(line.strip() for line in f)\n",
    "\n",
    "def save_processed_id(item_id, file_path):\n",
    "    \"\"\"保存已经处理过的 item_id\"\"\"\n",
    "    with open(file_path, 'a') as f:\n",
    "        f.write(f\"{item_id}\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "edf44110-22d8-4d89-b5ee-025e30449fcb",
   "metadata": {},
   "outputs": [],
   "source": [
    "def process_items(data, processed_ids_file='processed_ids.txt', output_file='results.json'):\n",
    "    results = []\n",
    "    processed_ids = load_processed_ids(processed_ids_file)  # 加载已经处理过的 item_id\n",
    "    encountered_connection_error = False  # 添加一个标志来记录是否遇到了连接错误\n",
    "    \n",
    "    for item in tqdm(data, desc=\"Processing items\"):\n",
    "        if encountered_connection_error:\n",
    "            break  # 如果遇到了连接错误，则不再处理后续项目\n",
    "            \n",
    "        item_id = item.get('id', '')\n",
    "        # 如果 item_id 已经被处理，则跳过\n",
    "        if item_id in processed_ids:\n",
    "            continue\n",
    "        # print(item)\n",
    "        image_urls = []  # 定义 image_urls 列表\n",
    "        # print(item.get('image'))\n",
    "        # print(isinstance(item['image'], list))\n",
    "        # print(len(item['image']))\n",
    "        if item.get('image') and isinstance(item['image'], list) and len(item['image']) > 0:\n",
    "            \n",
    "            # 如果图片超过4个，则只取最后的4个\n",
    "            images_to_process = item['image'][-4:] if len(item['image']) > 4 else item['image']\n",
    "            \n",
    "            for image_path in images_to_process:\n",
    "                try:\n",
    "                    # processed_image = preprocess_image(image_path)\n",
    "                    base64_image = image_to_base64(image_path)\n",
    "                    image_url = f\"data:image/png;base64,{base64_image}\"\n",
    "                    image_urls.append({\"type\": \"image_url\", \"image_url\": {\"url\": image_url}})\n",
    "                    # if len(image_urls) > 2:\n",
    "                    #     break\n",
    "                except Exception as e:\n",
    "                    print(f\"Error processing image for item {item_id}: {e}\")\n",
    "                    continue\n",
    "        template = item.get('instruction', '')\n",
    "        # print(image_urls)\n",
    "        input_data = {\n",
    "            \"role\": \"user\",\n",
    "            \"content\": image_urls + [{\"type\": \"text\", \"text\": template}] \n",
    "        }\n",
    "        # print(input_data)\n",
    "        # break\n",
    "        try:\n",
    "            # 调用处理链进行推理\n",
    "            # response = (prompt | model | output_parser).invoke(input=input_data)\n",
    "            completion = client.chat.completions.create(\n",
    "                model=modelname,\n",
    "                messages=[input_data]\n",
    "            )\n",
    "            # 提取完成信息中的文本部分，并处理为空的情况\n",
    "            if hasattr(completion, 'choices') and completion.choices:\n",
    "                completion_text = completion.choices[0].message.content\n",
    "            else:\n",
    "                print(f\"No choices found for item {item_id}\")\n",
    "                completion_text = \"\"\n",
    "            \n",
    "            expected_output = item.get('expected_output', '')  # 或者其他来源\n",
    "            \n",
    "            result = {\n",
    "                'item_id': item_id,\n",
    "                'image_path': image_path if base64_image else '',\n",
    "                'instruction': item.get('instruction', ''),\n",
    "                'expected_output': expected_output,\n",
    "                'prediction': completion_text,\n",
    "                'response_matches_expected': completion_text == expected_output\n",
    "            }\n",
    "            # print(result)\n",
    "            results.append(result)\n",
    "            save_processed_id(item_id, processed_ids_file)\n",
    "            \n",
    "            # 批量保存结果到 JSON 文件\n",
    "            if len(results) % 1000 == 0:  # 每1000个结果保存一次\n",
    "                timestamp = datetime.datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n",
    "                temp_output_file = f\"temp_results_{timestamp}.json\"\n",
    "                save_results_to_json(results, temp_output_file)\n",
    "            \n",
    "        except Exception as e:\n",
    "            if \"Connection error\" in str(e):\n",
    "                print(f\"Connection error invoking model for item {item_id}: {e}\")\n",
    "                print(\"Exiting due to connection error.\")\n",
    "                encountered_connection_error = True  # 设置标志为 True\n",
    "                break  # 立即退出循环\n",
    "            else:\n",
    "                print(f\"Error invoking model for item {item_id}: {e}\")\n",
    "                continue\n",
    "        # break\n",
    "    # 最后一次保存剩余的结果\n",
    "    if results:\n",
    "        save_results_to_json(results, output_file)\n",
    "    if encountered_connection_error:\n",
    "        sys.exit(1)  # 遇到连接错误时退出程序"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "7c5d54d2-f932-4885-80e3-992281e6f08f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'E:\\\\fxuanf\\\\02_AI_51\\\\01_Projects\\\\doraemon-bot\\\\datasets\\\\test1\\\\test1_fullpath.json'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test1_file_fullpath"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "99d3dcda-743a-4f9e-91a4-dec99c67f9b0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化变量\n",
    "results = []\n",
    "num_errors = 0\n",
    "# 加载训练数据\n",
    "data = load_data_from_json(test1_file_fullpath)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "1040be8a-7767-4ec2-a12b-c46a59abae7e",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Processing items:  69%|████████████████████████████████████████▋                  | 6893/10000 [47:44<23:06,  2.24it/s]D:\\ProgramData\\anaconda3\\Lib\\site-packages\\PIL\\Image.py:3368: DecompressionBombWarning: Image size (108576768 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack.\n",
      "  warnings.warn(\n",
      "Processing items:  80%|█████████████████████████████████████████████▋           | 8013/10000 [57:14<3:59:55,  7.24s/it]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Error invoking model for item 56be1ad2-64c6-4e6c-a27f-c5a0a91697ea-7495: Request timed out.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Processing items: 100%|████████████████████████████████████████████████████████| 10000/10000 [1:12:45<00:00,  2.29it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "所有结果都保存到 JSON 文件中了。结束\n"
     ]
    }
   ],
   "source": [
    "process_items(data)\n",
    "print(\"所有结果都保存到 JSON 文件中了。结束\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "4c00ebe8-e628-4d26-a0a9-baab590d396f",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Processing items: 100%|███████████████████████████████████████████████████████| 10000/10000 [00:00<00:00, 24423.37it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "所有结果都保存到 JSON 文件中了。结束\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "# 在执行一次，把报错的追加进去，超过4个图片的，只读取最后4张图片。\n",
    "process_items(data)\n",
    "print(\"所有结果都保存到 JSON 文件中了。结束\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "87095dab-28a4-4c6b-b697-8078ecb1367d",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fdcb64f7-20cd-45a5-8a08-91c51d185d2e",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f2e8a438-b013-4795-8eba-60b450210162",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
